import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QListWidget, QFileDialog  # 导入QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSignal, QResource, Qt
from pynput import mouse, keyboard
import pyautogui
import pydirectinput
import time
import threading
import math
import json
from concurrent.futures import ThreadPoolExecutor
import ctypes

# 获取系统的主要鼠标键设置
def is_left_button_primary():
    # 获取系统鼠标设置
    user32 = ctypes.windll.user32
    return user32.GetSystemMetrics(43) == 0  # 0 表示左键为主要键

normalMouse = False

class MainWindow(QMainWindow):
    my_signal = pyqtSignal(int)

    def __init__(self):
        super().__init__()

        self.setWindowTitle("AutoMater")
        self.setWindowIcon(QIcon('./icon.ico'))
        self.setGeometry(100, 100, 620, 400)
        self.setFixedSize(self.size())
        # 设置窗口总是在最前端显示
        # self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)

        self.isRecode = False
        self.isReplay = False
        self.isOnDrop = False
        self.isMoved  = False
        self.lastTime = time.perf_counter()
        self.replayTimes = -1
        self.lastMmouse = (0, 0)
        # 当前按平衡点的键的集合
        self.current_keys = set()
        global normalMouse
        normalMouse = is_left_button_primary()

        # 添加第一个按钮
        self.button1 = QPushButton('录制', self)
        self.button1.setGeometry(20, 10, 100, 50)  # 设置按钮位置和大小
        self.button1.clicked.connect(self.on_button1_clicked)  # 连接信号
        # 添加第二个按钮
        self.button2 = QPushButton('回放', self)
        self.button2.setGeometry(140, 10, 100, 50)  # 设置按钮位置和大小
        self.button2.clicked.connect(self.on_button2_clicked)

        self.button3 = QPushButton('清空', self)
        self.button3.setGeometry(260, 10, 100, 50)
        self.button3.clicked.connect(self.on_button3_clicked)

        self.button4 = QPushButton('保存', self)
        self.button4.setGeometry(380, 10, 100, 50)
        self.button4.clicked.connect(self.on_button4_clicked)

        self.button5 = QPushButton('打开', self)
        self.button5.setGeometry(500, 10, 100, 50)
        self.button5.clicked.connect(self.on_button5_clicked)

        # 初始化监听器引用
        self.mouse_listener = None
        self.keyboard_listener = None
        self.event_list = []
        self.replayThread = None
        self.stopReplayEvent = None
        self.my_signal.connect(self.updateListWidget)

        self.list_widget = QListWidget(self)
        self.list_widget.setGeometry(20, 70, 580, 300)

        # 创建并启动键盘监听器
        self.keyboard_listener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release)
        self.keyboard_listener.start()

    def closeEvent(self, event):
        self.isRecode = False
        self.isReplay = False
        if self.keyboard_listener is not None:
            self.keyboard_listener.stop()
        if self.mouse_listener is not None:
            self.mouse_listener.stop()
        if self.stopReplayEvent is not None:
            self.stopReplayEvent.set()
        event.accept()

    def on_button1_clicked(self):
        print("hello")  # 当按钮被点击时输出hello
        end_time = time.perf_counter()
        print("运行时间是：{:9.9}s".format(end_time - self.lastTime))
        if self.isRecode:
            self.recodeDelay()
            self.isRecode = False
            self.button1.setText('录制')
            self.button2.setEnabled(True)
            if self.mouse_listener is not None:
                self.mouse_listener.stop()
        else:
            self.lastTime = end_time
            self.isRecode = True
            self.button1.setText('停止')
            self.button2.setEnabled(False)
            # 启动鼠标监听器
            self.mouse_listener = mouse.Listener(on_move=self.on_move, on_click=self.on_click)
            self.mouse_listener.start()

    def on_button2_clicked(self):
        print("回放")
        if self.isReplay:
            self.isReplay = False
            self.button2.setText('开始回放')
            self.button1.setEnabled(True)
            if self.stopReplayEvent is not None:
                self.stopReplayEvent.set()
        else:
            self.isReplay = True
            self.button2.setText('停止回放')
            self.button1.setEnabled(False)
            self.stopReplayEvent = threading.Event()
            self.replayThread = threading.Thread(target=self.doReplay, args=(self.stopReplayEvent, self.my_signal,))
            self.replayThread.daemon = True
            self.replayThread.start()

    def on_button3_clicked(self):
        self.event_list = []
        self.list_widget.clear()

    def on_button4_clicked(self):
        options = QFileDialog.Options()
        filename, _ = QFileDialog.getSaveFileName(self, "保存自动化角本", "",
             "Text Files (*.txt);;All Files (*)", options=options)
        if filename:
            with open(filename, 'w') as file:
                for event in self.event_list:
                    event_str = json.dumps(event)
                    file.write(event_str + '\n')
        
    def on_button5_clicked(self):
        options = QFileDialog.Options()
        filename, _ = QFileDialog.getOpenFileName(self, "选择要打开的文件", "",
            "Text Files (*.txt);;All Files (*)", options=options)
        if filename:
            with open(filename, 'r') as file:
                self.list_widget.clear()
                self.event_list.clear()
                for line in file:
                    event = json.loads(line)
                    self.event_list.append(event)
                    self.list_widget.addItem(self.eventToStr(event))
    
    def eventToStr(self, event):
        if event['action'] == 'delay':
            return f"action: delay value: {event['value']}"
        elif event['action'] == 'Button.left' or event['action'] == 'Button.right':
            return f"action: {event['action']} in ({event['x']}, {event['y']}), pressed={event['pressed']}"
        elif event['action'] == 'move':
            return f"Mouse moved to ({event['x']}, {event['y']}) duration: {event['duration']}"
        elif event['action'] == 'key_up' or event['action'] == 'key_down':
            return f"action: {event['action']} for key {event['key']}"

    def doReplay(self, stop_event, update_signal):
        i = self.replayTimes
        compensator_time = 0.02  # 补偿时间
        sleep_compensator = 0     # sleep补偿
        with ThreadPoolExecutor(max_workers=3) as executor:
            time.sleep(1)
            while i != 0 and not stop_event.is_set():
                i = i-1
                for idx, action in enumerate(self.event_list):
                    #self.list_widget.setCurrentRow(idx) 不要在子线程中去修改UI
                    update_signal.emit(idx)
                    if stop_event.is_set():
                        break
                    if action['action'] == 'delay':
                        realSleep = action['value'] - sleep_compensator
                        if realSleep > 0: 
                            time.sleep(realSleep)
                            sleep_compensator = 0
                        else:
                            sleep_compensator -= action['value']
                    else :
                        executor.submit(task, action)
                        time.sleep(compensator_time)
                        sleep_compensator += compensator_time
                   
            executor.shutdown()
            print("线程池退出")



    def on_click(self, x, y, button, pressed):
        if pressed:
            self.isOnDrop = True
            self.isMoved = False
            self.lastMmouse = (x, y)
        else:
            if self.isMoved:
                self.recodeDrop({"x": x, "y": y, "action": "move", "pressed": True})
            self.isOnDrop = False
        self.recodeAction({"x": x, "y": y, "action": f"{button}", "pressed": pressed})
        print(self.event_list[-1])

    def on_move(self, x, y):
        if not self.isOnDrop:
            return
        if time.perf_counter() - self.lastTime < 0.02:
            return
        if zuobioaJuli(self.lastMmouse, (x, y)) < 20:
            return
        self.isMoved = True
        self.lastMmouse = (x, y)
        self.recodeDrop({"x": x, "y": y, "action": "move", "pressed": True})
        print(f"Mouse moved to ({x}, {y})")

    def on_press(self, key):
        try:
            #print(f"Key {key} pressed is ctrl: {key == keyboard.Key.ctrl_l}")
            print(f"press  key {str(key)} is Key: {isinstance(key, keyboard.Key)}")
            if not self.current_keys.__contains__(key):
                self.current_keys.add(key)
                if self.isRecode: 
                    if isinstance(key, keyboard.Key):
                        self.recodeKeyboard({"action":"key_down", "key":self.keyConvert(key)})
                    elif isinstance(key, keyboard.KeyCode):
                        self.recodeKeyboard({"action":"key_down", "key":self.keyCharConvert(key.char)})
        
            if self.current_keys.__contains__(keyboard.Key.f10) and self.current_keys.__contains__(keyboard.Key.ctrl_l) and not self.isReplay:
                print("Ctrl+F10 was pressed")
                if self.isRecode:
                    self.event_list = self.event_list[:-4]
                self.current_keys.clear()
                self.button1.click()
            if self.current_keys.__contains__(keyboard.Key.f2) and self.current_keys.__contains__(keyboard.Key.ctrl_l) and not self.isRecode:
                print("Ctrl+F2 was pressed")
                self.current_keys.clear()
                self.button2.click()
        except AttributeError:
            print(f"error  Special key {key} pressed")

    def on_release(self, key):
        try:
            print(f"Key {key} released")
            #if key == keyboard.Key.esc:
                # Stop listener
                # return False

            if self.isRecode and self.current_keys:
                if isinstance(key, keyboard.Key):
                    self.recodeKeyboard({"action":"key_up", "key":self.keyConvert(key)})
                elif isinstance(key, keyboard.KeyCode):
                    self.recodeKeyboard({"action":"key_up", "key":self.keyCharConvert(key.char)})
 
            self.current_keys.discard(key)
        except AttributeError:
            print(f"error     Special key {key} release")

    def keyConvert(self, key):
        if key == keyboard.Key.ctrl or key == keyboard.Key.ctrl_l:
            return 'ctrl'
        elif key == keyboard.Key.ctrl_r:
            return 'ctrlright'
        elif key == keyboard.Key.alt or key == keyboard.Key.alt_l:
            return 'alt'
        elif key == keyboard.Key.alt_r:
            return 'altright'
        elif key == keyboard.Key.cmd or key == keyboard.Key.cmd_l:
            return 'win'
        elif key == keyboard.Key.cmd_r:
            return 'winright'
        elif key == keyboard.Key.shift or key == keyboard.Key.shift_l:
            return 'shift'
        elif key == keyboard.Key.shift_r:
            return 'shiftright'
        elif key == keyboard.Key.caps_lock:
            return 'capslock'
        elif key == keyboard.Key.print_screen:
            return 'printscreen'
        elif key == keyboard.Key.scroll_lock:
            return 'scrolllock'
        else:
            keyStr = f"{key}"
            keyStr = keyStr[4:]
            return keyStr

    def keyCharConvert(self, code):
        ascii = ord(code)
        ascii = ascii if ascii >= 32 else ascii + 96
        return chr(ascii)

    def recodeDelay(self):
        current = time.perf_counter()
        delay = current - self.lastTime
        delay = round(delay, 4)
        self.lastTime = current
        self.event_list.append({"action": "delay", "value": delay})
        self.list_widget.setCurrentRow(len(self.event_list) - 1)

    def recodeAction(self, action):
        current = time.perf_counter()
        delay = current - self.lastTime
        delay = round(delay, 4)
        self.lastTime = current
        self.event_list.append({"action": "delay", "value": delay})
        self.event_list.append(action)
        self.list_widget.addItem(self.eventToStr(self.event_list[-2]))
        self.list_widget.addItem(self.eventToStr(self.event_list[-1]))
        self.list_widget.setCurrentRow(len(self.event_list) - 1)

    def recodeDrop(self, action):
        current = time.perf_counter()
        delay = current - self.lastTime
        self.lastTime = current
        action['duration'] = round(delay * 0.8, 4)
        self.event_list.append(action)
        self.event_list.append({"action": "delay", "value": delay})
        self.list_widget.addItem(self.eventToStr(self.event_list[-2]))
        self.list_widget.addItem(self.eventToStr(self.event_list[-1]))
        self.list_widget.setCurrentRow(len(self.event_list) - 1)

    def recodeKeyboard(self, action):
        current = time.perf_counter()
        delay = current - self.lastTime
        self.lastTime = current
        self.event_list.append({"action": "delay", "value": delay})
        self.event_list.append(action)
        self.list_widget.addItem(self.eventToStr(self.event_list[-2]))
        self.list_widget.addItem(self.eventToStr(self.event_list[-1]))
        self.list_widget.setCurrentRow(len(self.event_list) - 1)

    def updateListWidget(self, index):
        self.list_widget.setCurrentRow(index)
    
def zuobioaJuli(point1, point2):
    x1, y1 = point1[0], point1[1]
    x2, y2 = point2[0], point2[1]
    distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
    return distance

def task(action):
    if action['action'] == 'Button.left' and action['pressed'] :
        primary = 'left' if normalMouse else 'right'
        pydirectinput.mouseDown(x=action['x'], y=action['y'], button=primary)
    elif action['action'] == 'Button.left' and not action['pressed'] :
        primary = 'left' if normalMouse else 'right'
        pydirectinput.mouseUp(x=action['x'], y=action['y'], button=primary)
    elif action['action'] == 'Button.right' and action['pressed'] :
        secondary = 'right' if normalMouse else 'left'
        pydirectinput.mouseDown(x=action['x'], y=action['y'], button=secondary)
    elif action['action'] == 'Button.right' and not action['pressed'] :
        secondary = 'right' if normalMouse else 'left'
        pydirectinput.mouseUp(x=action['x'], y=action['y'], button=secondary)
    elif action['action'] == 'move':
        pydirectinput.moveTo(action['x'], action['y'], duration=action['duration'])
    elif action['action'] == 'key_down':
        pydirectinput.keyDown(action['key'])
    elif action['action'] == 'key_up':
        pydirectinput.keyUp(action['key'])
    

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()

    sys.exit(app.exec_())

